// call方法：
// 用于调用一个函数，显示指定函数内部的this指向，参数以列表的形式传的参数给函数
// 语法：func.call(thisArg,arg1,arg2,arg3,arg4,...)
// 直接调用函数，立即执行
// 用法与模拟实现
Function.prototype.mycall = function (context, ...args) {
    context = context || window; //如果没有传入上下文，则默认全局对象
    const uniqueID = Symbol(); //创建一个唯一的key
    context[uniqueID] = this; //将函数挂载到上下文对象上
    console.log(context);
    const result = context[uniqueID](...args); //调用函数
    delete context[uniqueID]; //删除函数
    return result; //返回函数执行结果
}


function greet(message) {
    console.log(`${message}, ${this.name}`);
}

const persion = {
    name: 'jidongDSB'
}

greet.mycall(persion, 'hello'); //hello, jidongDSB
greet.call(persion, 'hello'); //hello, jidongDSB

// apply方法：
// 用于调用一个函数，显示指定函数内部的this指向，参数以数组的形式传的参数给函数
// 语法： func.apply(context, [arg1,arg2,arg3,arg4,...])
// 用法与模拟实现
Function.prototype.myApply = function (context, args) {
    context = context || window; //如果没有上下文，则默认全局对象
    const uniqueID = Symbol(); //创建一个唯一的key
    context[uniqueID] = this; //将函数挂载到上下文对象上
    const result = context[uniqueID](...args); //调用函数
    delete context[uniqueID]; //删除函数
    return result; //返回函数执行结果
}

greet.myApply(persion, ['hello']); //hello, jidongDSB
greet.apply(persion, ['hello'])


// bind方法：
// bind方法不会立即调用函数，而是创建一个新的函数，该函数的this指向bind的第一个参数指定，参数以列表的形式传的参数给函数
// 语法: newFunc = function.bind(thisArg, arg1, arg2, arg3, arg4, ...)
// 不会立即执行，而是返回一个新的函数
// 用法与模拟实现
Function.prototype.myBind = function (context, ...args) {
    const func = this
    return function (...newArgs) {
        return func.apply(context, args.concat(newArgs))
    }
}

const myBoundGreet = greet.myBind(persion, 'hello')
myBoundGreet()
const myBoundGreet2 = greet.bind(persion, 'hello')
myBoundGreet2()